package org.traffometer.traffosim.gui.controller;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;

import org.traffometer.traffosim.gui.model.ConfigModel;
import org.traffometer.traffosim.gui.view.View;

/**
 * Implements the Controller component of the MVC pattern for the Traffometer GUI. The
 * model is an instance of ConfigModel, and the view is an instance of View.
 * 
 * @author George Lee
 */
public class GUIController {
  /**The instance of ConfigModel that will be updated by the listeners.*/
  private final ConfigModel config;

  /**
   * Create an instance of a Controller that will tie together the passed Model and View.
   * 
   * @param model The model, an instance of ConfigModel.
   * @param view The View, which will display the ConfigModel state and support operations on it.
   */
  public GUIController(ConfigModel model, View view) {
    this.config = model;
    model.addObserver(view);

    view.addBatchRateDocListener(new BatchRateDocListener());
    view.addStartLatDocListener(new StartLatDocListener());
    view.addStartLngDocListener(new StartLngDocListener());
    view.addStartTimeDocListener(new StartTimeDocListener());

    view.addEndLatDocListener(new EndLatDocListener());
    view.addEndLngDocListener(new EndLngDocListener());
    view.addEndTimeDocListener(new EndTimeDocListener());

    view.addVehicleDocListener(new VehicleDocListener());
    view.addPacketListener(new AddPacketListener());
    view.addSaveListener(new SaveConfigListener());

    view.showGUI();
  }

  /**
   * Provides the listener that responds to inputting text into the batch rate field.
   * 
   * @author George Lee
   */
  private class BatchRateDocListener implements DocumentListener {

    /**
     * Called when the style of the text is changed.
     * 
     * @param event The event sent by the view.
     */
    public void changedUpdate(DocumentEvent event) {
      //Never called using plain text.
    }

    /**
     * Called when text is inserted into the text box.
     * 
     * @param event The event sent by the view.
     */
    public void insertUpdate(DocumentEvent event) {
      Document doc = event.getDocument();
      int start = doc.getStartPosition().getOffset();
      int length = doc.getLength();
      try {
        config.setBatchRate(doc.getText(start, length));
      }
      catch (BadLocationException e) {
        System.err.println("Batch rate error.");
        e.printStackTrace();
      }
    }

    /**
     * Called when text is removed from the text box.
     * 
     * @param event The event sent by the view.
     */
    public void removeUpdate(DocumentEvent event) {
      Document doc = event.getDocument();
      int start = doc.getStartPosition().getOffset();
      int length = doc.getLength();
      try {
        config.setBatchRate(doc.getText(start, length));
      }
      catch (BadLocationException e) {
        System.err.println("Batch rate error.");
        e.printStackTrace();
      }
    }

  }

  /**
   * Provides the listener that responds to changes in the starting latitude field.
   * 
   * @author George Lee
   */
  private class StartLatDocListener implements DocumentListener {

    /**
     * Called when the style of the text is changed.
     * 
     * @param event The event sent by the view.
     */
    public void changedUpdate(DocumentEvent event) {
      //Never called using plain text.
    }

    /**
     * Called when text is inserted into the text box.
     * 
     * @param event The event sent by the view.
     */
    public void insertUpdate(DocumentEvent event) {
      Document doc = event.getDocument();
      int start = doc.getStartPosition().getOffset();
      int length = doc.getLength();
      try {
        config.setStartLat(doc.getText(start, length));
      }
      catch (BadLocationException e) {
        System.err.println("Starting latitude text retrieval error.");
        e.printStackTrace();
      }
    }

    /**
     * Called when text is removed from the text box.
     * 
     * @param event The event sent by the view.
     */
    public void removeUpdate(DocumentEvent event) {
      Document doc = event.getDocument();
      int start = doc.getStartPosition().getOffset();
      int length = doc.getLength();
      try {
        config.setStartLat(doc.getText(start, length));
      }
      catch (BadLocationException e) {
        System.err.println("Starting latitude text removal error.");
        e.printStackTrace();
      }
    }

  }

  /**
   * Provides the listener that responds to inputting text into the starting longitude field.
   * 
   * @author George Lee
   */
  private class StartLngDocListener implements DocumentListener {

    /**
     * Called when the style of the text is changed.
     * 
     * @param event The event sent by the view.
     */
    public void changedUpdate(DocumentEvent event) {
      //Never called using plain text.
    }

    /**
     * Called when text is inserted into the text box.
     * 
     * @param event The event sent by the view.
     */
    public void insertUpdate(DocumentEvent event) {
      Document doc = event.getDocument();
      int start = doc.getStartPosition().getOffset();
      int length = doc.getLength();
      try {
        config.setStartLong(doc.getText(start, length));
      }
      catch (BadLocationException e) {
        System.err.println("Starting longitude text retrieval error.");
        e.printStackTrace();
      }
    }

    /**
     * Called when text is removed from the text box.
     * 
     * @param event The event sent by the view.
     */
    public void removeUpdate(DocumentEvent event) {
      Document doc = event.getDocument();
      int start = doc.getStartPosition().getOffset();
      int length = doc.getLength();
      try {
        config.setStartLong(doc.getText(start, length));
      }
      catch (BadLocationException e) {
        System.err.println("Starting longitude text removal error.");
        e.printStackTrace();
      }
    }

  }

  /**
   * Provides the listener that responds to inputting text into the starting time field.
   * 
   * @author George Lee
   */
  private class StartTimeDocListener implements DocumentListener {

    /**
     * Called when the style of the text is changed.
     * 
     * @param event The event sent by the view.
     */
    public void changedUpdate(DocumentEvent event) {
      //Never called using plain text.
    }

    /**
     * Called when text is inserted into the text box.
     * 
     * @param event The event sent by the view.
     */
    public void insertUpdate(DocumentEvent event) {
      Document doc = event.getDocument();
      int start = doc.getStartPosition().getOffset();
      int length = doc.getLength();
      try {
        config.setStartTime(doc.getText(start, length));
      }
      catch (BadLocationException e) {
        System.err.println("Starting time text retrieval error.");
        e.printStackTrace();
      }
    }

    /**
     * Called when text is removed from the text box.
     * 
     * @param event The event sent by the view.
     */
    public void removeUpdate(DocumentEvent event) {
      Document doc = event.getDocument();
      int start = doc.getStartPosition().getOffset();
      int length = doc.getLength();
      try {
        config.setStartTime(doc.getText(start, length));
      }
      catch (BadLocationException e) {
        System.err.println("Starting time text removal error.");
        e.printStackTrace();
      }
    }

  }

  /**
   * Provides the listener that responds to inputting text into the ending latitude field.
   * 
   * @author George Lee
   */
  private class EndLatDocListener implements DocumentListener {

    /**
     * Called when the style of the text is changed.
     * 
     * @param event The event sent by the view.
     */
    public void changedUpdate(DocumentEvent event) {
      //Never called using plain text.
    }

    /**
     * Called when text is inserted into the text box.
     * 
     * @param event The event sent by the view.
     */
    public void insertUpdate(DocumentEvent event) {
      Document doc = event.getDocument();
      int start = doc.getStartPosition().getOffset();
      int length = doc.getLength();
      try {
        config.setEndLat(doc.getText(start, length));
      }
      catch (BadLocationException e) {
        System.err.println("Ending latitude text retrieval error.");
        e.printStackTrace();
      }
    }

    /**
     * Called when text is removed from the text box.
     * 
     * @param event The event sent by the view.
     */
    public void removeUpdate(DocumentEvent event) {
      Document doc = event.getDocument();
      int start = doc.getStartPosition().getOffset();
      int length = doc.getLength();
      try {
        config.setEndLat(doc.getText(start, length));
      }
      catch (BadLocationException e) {
        System.err.println("Ending latitude text removal error.");
        e.printStackTrace();
      }
    }

  }

  /**
   * Provides the listener that responds to inputting text into the ending longitude field.
   * 
   * @author George Lee
   */
  private class EndLngDocListener implements DocumentListener {

    /**
     * Called when the style of the text is changed.
     * 
     * @param event The event sent by the view.
     */
    public void changedUpdate(DocumentEvent event) {
      //Never called using plain text.
    }

    /**
     * Called when text is inserted into the text box.
     * 
     * @param event The event sent by the view.
     */
    public void insertUpdate(DocumentEvent event) {
      Document doc = event.getDocument();
      int start = doc.getStartPosition().getOffset();
      int length = doc.getLength();
      try {
        config.setEndLong(doc.getText(start, length));
      }
      catch (BadLocationException e) {
        System.err.println("Ending longitude text retrieval error.");
        e.printStackTrace();
      }
    }

    /**
     * Called when text is removed from the text box.
     * 
     * @param event The event sent by the view.
     */
    public void removeUpdate(DocumentEvent event) {
      Document doc = event.getDocument();
      int start = doc.getStartPosition().getOffset();
      int length = doc.getLength();
      try {
        config.setEndLong(doc.getText(start, length));
      }
      catch (BadLocationException e) {
        System.err.println("Ending latitude text removal error.");
        e.printStackTrace();
      }
    }

  }

  /**
   * Provides the listener that responds to inputting text into the ending time field.
   * 
   * @author George Lee
   */
  private class EndTimeDocListener implements DocumentListener {

    /**
     * Called when the style of the text is changed.
     * 
     * @param event The event sent by the view.
     */
    public void changedUpdate(DocumentEvent event) {
      //Never called using plain text.
    }

    /**
     * Called when text is inserted into the text box.
     * 
     * @param event The event sent by the view.
     */
    public void insertUpdate(DocumentEvent event) {
      Document doc = event.getDocument();
      int start = doc.getStartPosition().getOffset();
      int length = doc.getLength();
      try {
        config.setEndTime(doc.getText(start, length));
      }
      catch (BadLocationException e) {
        System.err.println("Ending time text retrieval error.");
        e.printStackTrace();
      }
    }

    /**
     * Called when text is removed from the text box.
     * 
     * @param event The event sent by the view.
     */
    public void removeUpdate(DocumentEvent event) {
      Document doc = event.getDocument();
      int start = doc.getStartPosition().getOffset();
      int length = doc.getLength();
      try {
        config.setEndTime(doc.getText(start, length));
      }
      catch (BadLocationException e) {
        System.err.println("Ending latitude text removal error.");
        e.printStackTrace();
      }
    }

  }

  /**
   * Provides the listener that responds to inputting text into the vehicle field.
   * 
   * @author George Lee
   */
  private class VehicleDocListener implements DocumentListener {

    /**
     * Called when the style of the text is changed.
     * 
     * @param event The event sent by the view.
     */
    public void changedUpdate(DocumentEvent event) {
      //Never called using plain text.
    }

    /**
     * Called when text is inserted into the text box.
     * 
     * @param event The event sent by the view.
     */
    public void insertUpdate(DocumentEvent event) {
      Document doc = event.getDocument();
      int start = doc.getStartPosition().getOffset();
      int length = doc.getLength();
      try {
        config.setVehicle(doc.getText(start, length));
      }
      catch (BadLocationException e) {
        System.err.println("Vehicle text retrieval error.");
        e.printStackTrace();
      }
    }

    /**
     * Called when text is removed from the text box.
     * 
     * @param event The event sent by the view.
     */
    public void removeUpdate(DocumentEvent event) {
      Document doc = event.getDocument();
      int start = doc.getStartPosition().getOffset();
      int length = doc.getLength();
      try {
        config.setVehicle(doc.getText(start, length));
      }
      catch (BadLocationException e) {
        System.err.println("Vehicle text removal error.");
        e.printStackTrace();
      }
    }

  }

  /**
   * Provides the listener that responds to pushing the Add Packet button.
   * 
   * @author George Lee
   */
  private class AddPacketListener implements ActionListener {
    /**
     * Responds to button press by adding a packet to the ConfigWriter.
     * @param e The button press event.
     */
    public void actionPerformed(ActionEvent e) {
      config.addPacket();
    }
  }

  /**
   * Provides the listener that responds to pushing the Save Config button.
   * 
   * @author George Lee
   */
  private class SaveConfigListener implements ActionListener {
    /**
     * Responds to button press by saving the configuration.
     * 
     * @param e The button press event.
     */
    public void actionPerformed(ActionEvent e) {
      //Save to default for now.
      config.saveFile("");
    }
  }
}
